#ifndef TRANSFORMER_H
#define TRANSFORMER_H

#include <BLineArray>
#include <BViewer>
#include <BBillboard>
#include <BLine>
#include <BQuad>
#include <BCone>
#include <BSphere>
#include <BPicker>
#include <BRoundHandler>

#include "Config.h"
#include "operas/TransOpera.h"
#include "notes/TransformNote.h"
#include "notes/RotationNote.h"
#include "notes/ScalingNote.h"

enum HandleMode
{
	HM_None = (int)0,
	HM_Move,
	HM_Rotate,
	HM_Scale,
	HM_Max,
};

enum HandleAxis
{
	HA_None = (int)0,
	HA_X	= 0x01,
	HA_Y	= 0x02,
	HA_Z	= 0x04,
	HA_XY	= HA_X | HA_Y,
	HA_XZ	= HA_X | HA_Z,
	HA_YZ	= HA_Y | HA_Z,
	HA_XYZ	= HA_X | HA_Y | HA_Z,
	HA_Max
};

class TransformHandler : public BHandler
{
public:
	TransformHandler();
	~TransformHandler();

	void setConfig(Config* config);
	Config* config() const;

	void setHandleMode(HandleMode	mode);
	HandleMode handleMode() const;

	void setBasicMatrix(const BMatrix& basicMatrix);
	const BMatrix& basicMatrix() const;

	void setOrigin(const BMatrix& origin);
	const BMatrix& origin() const;

	void setMatrix(const BMatrix& matrix);
	const BMatrix& matrix() const;

	void dirtyAxis();

protected:
	void freshMoveAxis();
	void freshRotateAxis();
	void freshScaleAxis();

	bool pickMoveAxis(const BLine& line);
	bool pickRotateAxis(const BLine& line);
	bool pickScaleAxis(const BLine& line);

	void applyMoveOpera(const BLine& line);
	void applyRotateOpera(const BLine& line);
	void applyScaleOpera(const BLine& line);

	void drawAnchorAxis(BRender& render);
	void drawMoveAxis(BRender& render);
	void drawRotateAxis(BRender& render);
	void drawScaleAxis(BRender& render);

protected:
	virtual void startTransform(const BMatrix& matrix) = 0;
	virtual void transforming(const BMatrix& matrix) = 0;
	virtual void finishTransform(const BMatrix& matrix) = 0;

protected:
	void slotTargetChanged(BObject* object, const BValue& value);
	void slotCameraFocusFinished(BObject* object, const BValue& value);

protected:
	virtual void render(BRender& render);

	virtual void attachEvent(const BEvent& event);
	virtual void detachEvent(const BEvent& event);

	virtual void freshEvent(const BEvent& event);

	virtual void keyPressEvent(const BKeyEvent& keyEvent);
	virtual void keyReleaseEvent(const BKeyEvent& keyEvent);

	virtual void mouseEnterEvent(const BMouseEvent& mouseEvent);
	virtual void mouseLeaveEvent(const BMouseEvent& mouseEvent);
	virtual void mousePressEvent(const BMouseEvent& mouseEvent);
	virtual void mouseReleaseEvent(const BMouseEvent& mouseEvent);
	virtual void mouseMoveEvent(const BMouseEvent& mouseEvent);

	virtual void mouseWheelEvent(const BMouseEvent& mouseEvent);

private:
	BHolder<Config>			_config;
	BMatrix					_basicMatrix;
	BMatrix					_origin;
	BMatrix					_matrix;

	BReal					_axisSize;
	HandleMode				_handleMode;
	HandleAxis				_handleAxis;

	bool					_dirtyAxis;
	BLine					_axis_x;
	BLine					_axis_y;
	BLine					_axis_z;
	BConeHolder				_cone_x;
	BConeHolder				_cone_y;
	BConeHolder				_cone_z;
	BQuadf					_quad_xy;
	BQuadf					_quad_yz;
	BQuadf					_quad_xz;
	BBox					_box_x;
	BBox					_box_y;
	BBox					_box_z;

	int						_circleSegments;
	BVectorArray			_rotateCircleXY;
	BVectorArray			_rotateCircleYZ;
	BVectorArray			_rotateCircleXZ;
	BHolder<BSphere>		_rotateSphere;

	bool					_spaceShown;
	bool					_leftPressed;
	BLine					_linePressed;

};

#endif